//变量的解构赋值
//允许指定默认值
var [foo = true] = [];
foo // true

//如果一个数组成员不严格等于undefined，默认值是不会生效的。
var [x = 1] = [null];
x // null

function f() {
  console.log('aaa');
}

//表达式是惰性求值的
var [x = f()] = [1];

//上面代码等价于
var x;
if ([1][0] === undefined) {
  x = f();
} else {
    x = [1][0];
}

//对象的解构与数组有一个重要的不同。数组的元素是按次序排列的，变量的取值由它的位置决定；而对象的属性没有次序，变量必须与属性同名，才能取到正确的值。
//对象的解构赋值的内部机制，是先找到同名属性，然后再赋给对应的变量。真正被赋值的是后者，而不是前者。
var { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"
foo // error: foo is not defined

//只有var命令允许重新声明, let const 都不行
let test;
//如果要将一个已经声明的变量用于解构赋值，必须非常小心。因为JavaScript引擎会将{x}理解成一个代码块，从而发生语法错误。
//{test} = {test: 1}; // Unexpected token =
({test} = {test: 1}); // 放在圆括号里才可以 

//解构赋值的规则是，只要等号右边的值不是对象，就先将其转为对象。由于undefined和null无法转为对象，所以对它们进行解构赋值，都会报错。
//let { prop: prop } = undefined; //Cannot match against 'undefined' or 'null'.


//函数参数的解构也可以使用默认值。
function move({x = 0, y = 0} = {}) {
  return [x, y];
}

move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]
//上面代码中，函数move的参数是一个对象，通过对这个对象进行解构，得到变量x和y的值。如果解构失败，x和y等于默认值。


//可以使用圆括号的情况只有一种：赋值语句的非模式部分，可以使用圆括号。
let b, d;
[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确


//用途
//let [l = y, y = 1] = []; //y is undefined
//1.从函数返回多个值(把值放到对象或数组里),方便取值
function example() {
  return {
    foo: 1,
    bar: 2
  };
}
var { foo, bar } = example();

//2.变量交换
var x = 'hello', y = 'world';
[x, y] = [y, x]; //牛B
console.log(x + ' ' +  y);
